package com.mxpio.erp.plan.mrp.policy.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.druid.util.StringUtils;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.PlanEnums;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.plan.entity.*;
import com.mxpio.erp.common.plan.service.SalePredictionOffsettingFlowService;
import com.mxpio.erp.common.quality.entity.SoInQualityOrder;
import com.mxpio.erp.common.quality.entity.SoInQualityOrderLine;
import com.mxpio.erp.common.sales.entity.*;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpio.erp.plan.util.PlanDateUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.plan.mrp.Context;
import com.mxpio.erp.plan.mrp.CountModelMap;
import com.mxpio.erp.plan.mrp.bo.CountModel;
import com.mxpio.erp.plan.mrp.policy.LrpSalesOrderPolicy;
import com.mxpioframework.jpa.JpaUtil;

/**
 * 计算所有主计划汇总
 * @author maxp
 *
 */
@Component
public class SalesOrderPolicy extends LrpSalesOrderPolicy {
	@Autowired
	private OrderLineService bizOrderLineService;
	@Autowired
	private SalePredictionOffsettingFlowService salePredictionOffsettingFlowService;
	// 销售相关计划汇总(销售/组织需求/预留需求)
	@Override
	public void apply(Context context) {
		List<MpsVersion> effectiveMpsVersions = JpaUtil.linq(MpsVersion.class)
				.equal("bpmnStatus", OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())
				.equal("effectiveStatus", PlanEnums.EffectiveStatus.YES.getCode())
				.list();
		if (effectiveMpsVersions.isEmpty()){
			return ;
		}
		MpsVersion mpsVersion = effectiveMpsVersions.get(0);//生效的主计划版本数据
		String type = mpsVersion.getType();//PlanEnums.PlanType
		CountModelMap<List<CountModel>> result = new CountModelMap<List<CountModel>>();
		if (StringUtils.equals(PlanEnums.PlanType.STATIC.getCode(),type)){//静态计划
			List<MpsLine> mpsLines = JpaUtil.linq(MpsLine.class)
					.equal("versionCode", mpsVersion.getCode())
					.list();
			if(!mpsLines.isEmpty()){
				/*for(MpsLine mpl : mpsLines){//不从版本行中取数，改为行对应的原业务单据明细取数
					try {
						CountModel countModel = new CountModel();
						countModel.setCount(mpl.getQuantity());
						countModel.setItemCode(mpl.getItemCode());
						countModel.setOrderDate(mpl.getDeliveryDate());
						countModel.setRemark(mpl.getBizNo());
						countModel.setType(1);
						indexProcessAdd(context, mpl, result, countModel);
					}catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}*/
				Map<String, List<MpsLine>> linesGroupByTypeMap = mpsLines.stream().collect(Collectors.groupingBy(MpsLine::getDataType));
				if (linesGroupByTypeMap.containsKey(PlanEnums.DataType.SALES.getCode())){//销售订单
					List<SalesOrderLine> taskLine = new ArrayList<>();

					List<MpsLine> mpsLineList = linesGroupByTypeMap.get(PlanEnums.DataType.SALES.getCode());
					Map<String, List<MpsLine>> mpsBizAndLineMap = mpsLineList.stream().collect(Collectors.groupingBy(MpsLine::getBizNo));
					Set<String> bizNoSet = mpsLineList.stream().map(MpsLine::getBizNo).collect(Collectors.toSet());

					List<SalesOrderLine> salesOrderLineList = JpaUtil.linq(SalesOrderLine.class).in("bizNo", bizNoSet).list();
					Map<String, List<SalesOrderLine>> bizAndLinesMap = salesOrderLineList.stream().collect(Collectors.groupingBy(SalesOrderLine::getBizNo));

					for(String bizNo:mpsBizAndLineMap.keySet()){
						List<MpsLine> mpsLineListSub = mpsBizAndLineMap.get(bizNo);
						List<SalesOrderLine> salesOrderLinesSub = bizAndLinesMap.get(bizNo);
						Map<Object, SalesOrderLine> lineNoMap = JpaUtil.index(salesOrderLinesSub, "lineNo");
						for (MpsLine subline:mpsLineListSub){
							SalesOrderLine salesOrderLine = lineNoMap.get(subline.getBizLineNo());
							if (salesOrderLine!=null){
								taskLine.add(salesOrderLine);//找到原业务单据行
							}
						}
					}

					if (!taskLine.isEmpty()){
						NoticeClassVo shippingNoticeClazz = new NoticeClassVo(ShippingNotice.class, ShippingNoticeLine.class);
						NoticeClassVo rejectBillNoticeClazz = new NoticeClassVo(RejectBill.class, RejectBillLine.class);
						NoticeClassVo inQualityOrderClazz = new NoticeClassVo(SoInQualityOrder.class, SoInQualityOrderLine.class);//增加入库验收单 数据统计
						List<NoticeClassVo> noticeClassVos = new ArrayList<NoticeClassVo>();
						noticeClassVos.add(shippingNoticeClazz);
						noticeClassVos.add(rejectBillNoticeClazz);
						noticeClassVos.add(inQualityOrderClazz);
						bizOrderLineService.handleBizOrderLineQuantity(taskLine, noticeClassVos, OrderEnums.AccessType.OUT.getCode());
						for(SalesOrderLine salesOrderLine : taskLine){
							try{
								BigDecimal lastQuantity = salesOrderLine.getQuantity().subtract(salesOrderLine.getActualQuantity());
								if(lastQuantity.compareTo(BigDecimal.ZERO)>0){
									CountModel countMode = new CountModel();
									countMode.setCount(lastQuantity);
									countMode.setOrderDate(salesOrderLine.getDeliverDate());
									countMode.setItemCode(salesOrderLine.getItemCode());
									countMode.setType(1);
									indexProcessAdd(context, salesOrderLine, result, countMode);
								}
							}catch (Exception e) {
								e.printStackTrace();
								continue;
							}
						}
					}
				}
				if (linesGroupByTypeMap.containsKey(PlanEnums.DataType.OD.getCode())){//组织需求
					List<OrganizationDemandLine> taskLine = new ArrayList<>();

					List<MpsLine> mpsLineList = linesGroupByTypeMap.get(PlanEnums.DataType.OD.getCode());
					Map<String, List<MpsLine>> mpsBizAndLineMap = mpsLineList.stream().collect(Collectors.groupingBy(MpsLine::getBizNo));
					Set<String> bizNoSet = mpsLineList.stream().map(MpsLine::getBizNo).collect(Collectors.toSet());

					List<OrganizationDemandLine> organizationDemandLineList = JpaUtil.linq(OrganizationDemandLine.class).in("bizNo", bizNoSet).list();
					Map<String, List<OrganizationDemandLine>> bizAndLinesMap = organizationDemandLineList.stream().collect(Collectors.groupingBy(OrganizationDemandLine::getBizNo));

					for(String bizNo:mpsBizAndLineMap.keySet()){
						List<MpsLine> mpsLineListSub = mpsBizAndLineMap.get(bizNo);
						List<OrganizationDemandLine> organizationDemandLines = bizAndLinesMap.get(bizNo);
						Map<Object, OrganizationDemandLine> lineNoMap = JpaUtil.index(organizationDemandLines, "lineNo");
						for (MpsLine subline:mpsLineListSub){
							OrganizationDemandLine line = lineNoMap.get(subline.getBizLineNo());
							if (line!=null){
								taskLine.add(line);//找到原业务单据行
							}
						}
					}

					if (!taskLine.isEmpty()){
						NoticeClassVo oDReceivingNoticeClazz = new NoticeClassVo(ODReceivingNotice.class, ODReceivingNoticeLine.class);
						NoticeClassVo oDRejectNotice = new NoticeClassVo(ODRejectNotice.class, ODRejectNoticeLine.class);
						NoticeClassVo oDSupplementNotice = new NoticeClassVo(ODSupplementNotice.class, ODSupplementNoticeLine.class);
						NoticeClassVo oDDefectiveRejNotice = new NoticeClassVo(ODDefectiveRejNotice.class, ODDefectiveRejNoticeLine.class);
						List<NoticeClassVo> noticeClassVos = new ArrayList<>();
						noticeClassVos.add(oDReceivingNoticeClazz);
						noticeClassVos.add(oDRejectNotice);
						noticeClassVos.add(oDSupplementNotice);//退料时考虑补料部分
						noticeClassVos.add(oDDefectiveRejNotice);
						bizOrderLineService.handleBizOrderLineQuantity(taskLine, noticeClassVos, OrderEnums.AccessType.IN.getCode());
						for(OrganizationDemandLine odLine : taskLine){
							try{
								BigDecimal lastQuantity = odLine.getQuantity().subtract(odLine.getActualQuantity());
								if(lastQuantity.compareTo(BigDecimal.ZERO)>0){
									CountModel countMode = new CountModel();
									countMode.setCount(lastQuantity);
									countMode.setOrderDate(odLine.getDemandDate());
									countMode.setItemCode(odLine.getItemCode());
									countMode.setType(1);

									indexProcessAdd(context, odLine, result, countMode);
								}
							}catch (Exception e) {
								e.printStackTrace();
								continue;
							}
						}
					}
				}
				if (linesGroupByTypeMap.containsKey(PlanEnums.DataType.SP.getCode())){//销售预测
					List<SalePredictionLine> taskLine = new ArrayList<>();

					List<MpsLine> mpsLineList = linesGroupByTypeMap.get(PlanEnums.DataType.SP.getCode());
					Map<String, List<MpsLine>> mpsBizAndLineMap = mpsLineList.stream().collect(Collectors.groupingBy(MpsLine::getBizNo));
					Set<String> bizNoSet = mpsLineList.stream().map(MpsLine::getBizNo).collect(Collectors.toSet());

					List<SalePredictionLine> salePredictionLineList = JpaUtil.linq(SalePredictionLine.class).in("bizNo", bizNoSet).list();
					Map<String, List<SalePredictionLine>> bizAndLinesMap = salePredictionLineList.stream().collect(Collectors.groupingBy(SalePredictionLine::getBizNo));

					for(String bizNo:mpsBizAndLineMap.keySet()){
						List<MpsLine> mpsLineListSub = mpsBizAndLineMap.get(bizNo);
						List<SalePredictionLine> salePredictionLineListSub = bizAndLinesMap.get(bizNo);
						Map<Object, SalePredictionLine> lineNoMap = JpaUtil.index(salePredictionLineListSub, "lineNo");
						for (MpsLine subline:mpsLineListSub){
							SalePredictionLine line = lineNoMap.get(subline.getBizLineNo());
							if (line!=null){
								taskLine.add(line);//找到原业务单据行
							}
						}
					}

					if (!taskLine.isEmpty()){
						salePredictionOffsettingFlowService.handleQuantityFromSP(taskLine);//管理计算已核销数量
						for (SalePredictionLine line:taskLine){
							try{
								BigDecimal lastQuantity = line.getQuantity().subtract(line.getActualQuantity());
								if(lastQuantity.compareTo(BigDecimal.ZERO)>0){
									CountModel countMode = new CountModel();
									countMode.setCount(lastQuantity);
									countMode.setOrderDate(line.getDemandDate());
									countMode.setItemCode(line.getItemCode());
									countMode.setType(1);
									indexProcessAdd(context, line, result, countMode);
								}
							}catch (Exception e) {
								e.printStackTrace();
								continue;
							}
						}
					}
				}
			}
		}else if (StringUtils.equals(PlanEnums.PlanType.DYNAMIC.getCode(),type)){//动态计划
			Date now = PlanDateUtil.getIntegralStartTime(new Date()) ;//开始日期
			String rollPeriod = mpsVersion.getRollPeriod();//滚动周期
			Date rollPeriodDate = PlanDateUtil.getIntegralEndTime(PlanDateUtil.rollDay(now, Integer.parseInt(rollPeriod))) ;//结束日期
			//滚动销售
			Criteria criteria = Criteria.create();
			criteria.addCriterion("deliverDate", Operator.GE, now);
			criteria.addCriterion("deliverDate", Operator.LT, rollPeriodDate);//日期范围
			List<SalesOrderLine> salesOrderLines = JpaUtil.linq(SalesOrderLine.class)
					.exists(SalesOrder.class)
						.equalProperty("bizNo", "bizNo")
						.equal("bpmnStatus", OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())
						.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode())
						.notEqual("orderStatus", OrderStatusEnums.OrderStatus.FINISHED.getStatusCode())
						.notEqual("orderStatus", OrderStatusEnums.OrderStatus.CLEARED.getStatusCode())
					.end()
					.where(criteria)
					.list();
			if (!salesOrderLines.isEmpty()){
				NoticeClassVo shippingNoticeClazz = new NoticeClassVo(ShippingNotice.class, ShippingNoticeLine.class);
				NoticeClassVo rejectBillNoticeClazz = new NoticeClassVo(RejectBill.class, RejectBillLine.class);
				NoticeClassVo inQualityOrderClazz = new NoticeClassVo(SoInQualityOrder.class, SoInQualityOrderLine.class);//增加入库验收单 数据统计
				List<NoticeClassVo> noticeClassVos = new ArrayList<NoticeClassVo>();
				noticeClassVos.add(shippingNoticeClazz);
				noticeClassVos.add(rejectBillNoticeClazz);
				noticeClassVos.add(inQualityOrderClazz);
				bizOrderLineService.handleBizOrderLineQuantity(salesOrderLines, noticeClassVos, OrderEnums.AccessType.OUT.getCode());
				for(SalesOrderLine salesOrderLine : salesOrderLines){
					try{
						BigDecimal lastQuantity = salesOrderLine.getQuantity().subtract(salesOrderLine.getActualQuantity());
						if(lastQuantity.compareTo(BigDecimal.ZERO)>0){
							CountModel countMode = new CountModel();
							countMode.setCount(lastQuantity);
							countMode.setOrderDate(salesOrderLine.getDeliverDate());
							countMode.setItemCode(salesOrderLine.getItemCode());
							countMode.setType(1);

							indexProcessAdd(context, salesOrderLine, result, countMode);
						}
					}catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}
			}
			//组织需求：
			criteria = Criteria.create();
			criteria.addCriterion("demandDate", Operator.GE, now);
			criteria.addCriterion("demandDate", Operator.LT, rollPeriodDate);//日期范围
			List<OrganizationDemandLine> oDLines = JpaUtil.linq(OrganizationDemandLine.class)
					.exists(OrganizationDemand.class)
						.equalProperty("bizNo", "bizNo")
						.equal("bpmnStatus", OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())
						.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode())
						.notEqual("orderStatus", OrderStatusEnums.OrderStatus.FINISHED.getStatusCode())
						.notEqual("orderStatus", OrderStatusEnums.OrderStatus.CLEARED.getStatusCode())
					.end()
					.where(criteria)
					.list();
			if (!oDLines.isEmpty()){
				NoticeClassVo oDReceivingNoticeClazz = new NoticeClassVo(ODReceivingNotice.class, ODReceivingNoticeLine.class);
				NoticeClassVo oDRejectNotice = new NoticeClassVo(ODRejectNotice.class, ODRejectNoticeLine.class);
				NoticeClassVo oDSupplementNotice = new NoticeClassVo(ODSupplementNotice.class, ODSupplementNoticeLine.class);
				NoticeClassVo oDDefectiveRejNotice = new NoticeClassVo(ODDefectiveRejNotice.class, ODDefectiveRejNoticeLine.class);
				List<NoticeClassVo> noticeClassVos = new ArrayList<>();
				noticeClassVos.add(oDReceivingNoticeClazz);
				noticeClassVos.add(oDRejectNotice);
				noticeClassVos.add(oDSupplementNotice);//退料时考虑补料部分
				noticeClassVos.add(oDDefectiveRejNotice);
				bizOrderLineService.handleBizOrderLineQuantity(oDLines, noticeClassVos, OrderEnums.AccessType.IN.getCode());
				for(OrganizationDemandLine odLine : oDLines){
					try{
						BigDecimal lastQuantity = odLine.getQuantity().subtract(odLine.getActualQuantity());
						if(lastQuantity.compareTo(BigDecimal.ZERO)>0){
							CountModel countMode = new CountModel();
							countMode.setCount(lastQuantity);
							countMode.setOrderDate(odLine.getDemandDate());
							countMode.setItemCode(odLine.getItemCode());
							countMode.setType(1);

							indexProcessAdd(context, odLine, result, countMode);
						}
					}catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}
			}
			//销售预测
			criteria = Criteria.create();
			criteria.addCriterion("demandDate", Operator.GE, now);
			criteria.addCriterion("demandDate", Operator.LT, rollPeriodDate);//日期范围
			criteria.addCriterion("closeStatus",Operator.NE, OrderStatusEnums.CloseStatus.CLOSED.getStatusCode());//过滤掉已关闭数据
			List<SalePredictionLine> salePredictionLines = JpaUtil.linq(SalePredictionLine.class)
					.exists(SalePrediction.class)
					.equalProperty("bizNo", "bizNo")
					.equal("bpmnStatus", OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())
					.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode())
					.end()
					.where(criteria)
					.list();
			if (!salePredictionLines.isEmpty()){
				salePredictionOffsettingFlowService.handleQuantityFromSP(salePredictionLines);//管理计算已核销数量
				for (SalePredictionLine line:salePredictionLines){
					try{
						BigDecimal lastQuantity = line.getQuantity().subtract(line.getActualQuantity());
						if(lastQuantity.compareTo(BigDecimal.ZERO)>0){
							CountModel countMode = new CountModel();
							countMode.setCount(lastQuantity);
							countMode.setOrderDate(line.getDemandDate());
							countMode.setItemCode(line.getItemCode());
							countMode.setType(1);
							indexProcessAdd(context, line, result, countMode);
						}
					}catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}
			}
			//处理预留需求 由销售预测替代
			/*criteria = Criteria.create();
			criteria.addCriterion("deliveryDate", Operator.GE, now);
			criteria.addCriterion("deliveryDate", Operator.LT, rollPeriodDate);//日期范围
			List<MpsLine> mpsLines = JpaUtil.linq(MpsLine.class)
					.equal("dataType", PlanEnums.DataType.RESERVED.getCode())
					.equal("versionCode", mpsVersion.getCode())
					.where(criteria)
					.list();
			if(mpsLines.size()>0){
				for(MpsLine mpl : mpsLines){
					try {
						CountModel countModel = new CountModel();
						countModel.setCount(mpl.getQuantity());
						countModel.setItemCode(mpl.getItemCode());
						countModel.setOrderDate(mpl.getDeliveryDate());
						countModel.setRemark(mpl.getBizNo());
						countModel.setType(1);
						indexProcessAdd(context, mpl, result, countModel);
					}catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}
			}*/
		}
		context.setSalesOrderCount(result);

	}

}
